<?php
class Zen_Tree_Select extends Zen_List_Select {
	
	/**
	 * id родительского узла
	 * @var int
	 */
	private $parentId = 0;
	
	/**
	 * Глубина запроса
	 * @var int
	 */
	private $depth = 1;
	
	/**
	 * Типы
	 * @var int
	 */
	private $types = false;
	
	/**
	 * Выводить одномерный массив или многомерный
	 * @var boolean
	 */
	private $plain = true;
	
	/**
	 * Имя поля для дочерних узлов дерева
	 * @var string
	 */
	private $children = 'children';
	
	/**
	 * @return the $children
	 */
	public function getChildren() {
		return $this->children;
	}
	
	/**
	 * @param string $children
	 */
	public function setChildren($children) {
		$this->children = $children;
		return $this;
	}
	
	/**
	 * @return the $parentId
	 */
	public function getParentId() {
		return $this->parentId;
	}
	
	/**
	 * @param int $parentId
	 */
	public function setParentId($parentId) {
		$this->parentId = $parentId;
		return $this;
	}
	
	/**
	 * @return the $plain
	 */
	public function getPlain() {
		return $this->plain;
	}
	
	/**
	 * @param boolean $plain
	 */
	public function setPlain($plain) {
		$this->plain = $plain;
		return $this;
	}
	
	/**
	 * @return the $depth
	 */
	public function getDepth() {
		return $this->depth;
	}
	
	/**
	 * @param int $depth
	 */
	public function setDepth($depth) {
		$this->depth = $depth;
		return $this;
	}
	
	/**
	 * @return the $types
	 */
	public function getTypes() {
		return $this->types;
	}
	
	public function setTypes($types) {
		$defaultTypes = array ('core' => 'core', 'tree' => $this->getTableName () );
		$this->types = array_merge ( $defaultTypes, $types );
		return $this;
	}
	
	
	
	public function getOne($where = false) {
		$res = $this->getData($where);
		if($res){
			return $res[0];
		}else{
			return false;
		}
		
	}
	
	
	
	public function getData($where = false) {
		if($where){
			$this->setWhere($where);
		}
		$columns = $this->getColumns ();
		$types = $this->getTypes ();
		$thisTablename = $this->getTableName ();
		$table = $this->getTable ();
		$select = $table->select ()->setIntegrityCheck ( false );
		
		if ($columns == false || $columns == '*') {
			throw new Zend_Exception ( "Doesn't set columns for zend_tree_select" );
		} else {
			if (isset ( $columns ['tree'] )) {
				if ($this->getPlain () == false) {
					$left = false;
					if (! in_array ( 'left', $columns ['tree'] )) {
						$columns ['tree'] [] = 'left';
						$left = true;
					}
					$parent_id = false;
					if (! in_array ( 'parent_id', $columns ['tree'] )) {
						$columns ['tree'] [] = 'parent_id';
						$parent_id = true;
					}
				}
				$select->from ( array ('tree' => $thisTablename ), $columns ['tree'] );
				unset ( $columns ['tree'] );
			} else {
				$select->from ( array ('tree' => $thisTablename ), array ('*' ) );
			}
			
			foreach ( $columns as $type => $cols ) {
				if (isset ( $types [$type] )) {
					$joinColumns = array ();
					foreach ( $cols as $col ) {
						$joinColumns [$col . "[" . $types [$type] . "]"] = $col;
					}
					$select->joinLeft ( array ($type => $types [$type] ), '`tree`.`id` = `' . $type . '`.`id`', $joinColumns );
				} else {
					throw new Zend_Exception ( 'Doesnt set table for type ' . $type );
				}
			}
		}
		
		$order = $this->getOrder();
		$order = ($order) ? $order : "tree.left";
		$select->order ( $order );
		
		if($this->getParentId () == 0) {
			if($this->getDepth()>0){
				$select->where ( '`tree`.`level`<=?',$this->getDepth());
			}
		}else{
			$node = $this->getTable()->select()->where('id=?',$this->getParentId())->query()->fetchAll();
			
			if(isset($node[0])){
				$node = $node [0];
			}else{
				return false;
			}
			$select->where("`tree`.`left` >?", $node ['left'] )->where("`tree`.`right`<?",$node['right'])->where('`tree`.`level`>?',$node ['level']);
			
			if($this->getDepth()>0){
				$select->where ( '`tree`.`level`<=?', $node ['level'] + $this->getDepth());
			}
		}
		
		if ($this->getLimit()>=1){
			$select->limitPage($this->getPage(),$this->getLimit());
		}
		
		if($this->getWhere()){
			$select->where($this->getWhere());
		}
		
		if (($this->getPaging() != false) && ($this->getTotalcount () == 0)){
			$this->countpages($select);
		}
		$res = $select->query ()->fetchAll ();
		if ($res) {
			foreach ( $res as $key => $row ) {
				$fields = array ();
				foreach ( $row as $fieldName => $fieldValue ) {
					if (strpos($fieldName, ']') && isset($row['type'])) {
						if (strpos($fieldName, $row['type'] . ']') === false) {
							unset($row[$fieldName]);
							continue;
						}
					}
					$fname = preg_replace ( '/\[.*\]$/', '', $fieldName );
					if (! isset ( $fields [$fname] )) {
						$fields [$fname] = $fieldValue;
					} else {
						if ($fields [$fname] == "" && $fieldValue != "") {
							$fields [$fname] = $fieldValue;
						}
					}
				}
				$res [$key] = $fields;
			}
			if ($this->getPlain () == false) {
				$children = array ();
				$list = array ();
				foreach ( $res as $item ) {
					$list [$item ['id']] = $item;
				}
				$flat_list = $list;
				foreach ( $flat_list as $key => $data ) {
					$flat_list [$data ['parent_id']] [$this->getChildren()] [$key] = &$flat_list [$key];
				}
				
				
				$res = $flat_list [$this->getParentId()] [$this->getChildren()];
			}
		}
		return $res;
	}
	
	public function getBranch($id) {
		
		$columns = $this->getColumns ();
		$types = $this->getTypes ();
		$thisTablename = $this->getTableName ();
		$table = $this->getTable ();
		$select = $table->select ()->setIntegrityCheck ( false );
		
		if ($columns == false || $columns == '*') {
			throw new Zend_Exception ( "Doesn't set columns for zend_tree_select" );
		} else {
			if (isset ( $columns ['tree'] )) {
				if ($this->getPlain () == false) {
					$left = false;
					if (! in_array ( 'left', $columns ['tree'] )) {
						$columns ['tree'] [] = 'left';
						$left = true;
					}
					$parent_id = false;
					if (! in_array ( 'parent_id', $columns ['tree'] )) {
						$columns ['tree'] [] = 'parent_id';
						$parent_id = true;
					}
				}
				$select->from ( array ('tree' => $thisTablename ), $columns ['tree'] );
				unset ( $columns ['tree'] );
			} else {
				$select->from ( array ('tree' => $thisTablename ), array ('*' ) );
			}
			
			foreach ( $columns as $type => $cols ) {
				if (isset ( $types [$type] )) {
					$joinColumns = array ();
					foreach ( $cols as $col ) {
						$joinColumns [$col . "[" . $types [$type] . "]"] = $col;
					}
					$select->joinLeft ( array ($type => $types [$type] ), '`tree`.`id` = `' . $type . '`.`id`', $joinColumns );
				} else {
					throw new Zend_Exception ( 'Doesnt set table for type ' . $type );
				}
			}
		}
		
		$select->order ( "tree.left" );
		
		$node = $this->getTable()->find($id)->toArray();
		$node = $node [0];
		if($node)
		{	
			
			$select->where("`tree`.`left` <=?", $node ['left'] )->where("`tree`.`right`>=?",$node['right']);
		}else{
			throw new Zend_Exception ( 'Cant find row with id= ' . $id );
		}
		
		
		$res = $select->query ()->fetchAll ();
		
		if ($res) {
			foreach ( $res as $key => $row ) {
				$fields = array ();
				foreach ( $row as $fieldName => $fieldValue ) {
					$fname = preg_replace ( '/\[.*\]$/', '', $fieldName );
					if (! isset ( $fields [$fname] )) {
						$fields [$fname] = $fieldValue;
					} else {
						if ($fields [$fname] == "" && $fieldValue != "") {
							$fields [$fname] = $fieldValue;
						}
					}
				}
				$res [$key] = $fields;
			}
			
			if ($this->getPlain () == false) {
				$children = array ();
				$list = array ();
				foreach ( $res as $item ) {
					$list [$item ['id']] = $item;
				}
				$flat_list = $list;
				foreach ( $flat_list as $key => $data ) {
					$flat_list [$data ['parent_id']] [$this->getChildren()] [$key] = &$flat_list [$key];
				}
				$res = $flat_list [$this->getParentId()] [$this->getChildren()];
			}
		
		}
		return $res;
	}

}